<?php

namespace app\utils\ui\vue;

use app\utils\script\JSScript;
use app\utils\ui\native_element\Element;
use app\utils\ui\native_element\Text;
use app\utils\ui\Script;
use Exception;

/**
 * 在Vue中的处理函数
 */
class VueScript implements Script {

    private $data;
    private $method;
    private $handler;
    private $query;
    /**
     * @param string $query 定义vue的app的位置
     * @param array $data 定义的数据
     * @param array $method 函数名字，[ { method, } ]
     * @param array $handler 处理method和data的JS代码，key为函数名称，value为JS脚本或是JSScript 对象
     */
    public function __construct(string $query,array $data,array $method,array $handler)
    {
        $this->query=$query;
        $this->data=$data;
        $this->method=$method;
        $this->handler=$handler;
    }


    /**
     * vue 3，vue实例：app
     * @param string $before 输出vue主体之前
     * @param string $before_mount 初始化应用vue之前
     */
    public function app_script($before,$before_mount=''){
        $html=$before;
        $method_script=array();

        //备份
        $lasted = $this->handler;
        foreach($this->method as $item){
            if(isset($item['method'])){
                if($item['method']){
                    $method =$item['method'];
                    if(strpos($method,'{') && strpos($method,'}') && strpos($method,'(') && strpos($method,')')  && strpos($method,'=>') ){
                        //METHOD 中包含(){} 符号视为一个完整匿名函数
                        $method_script[]=$method;
                    }else{
                        if(strpos($method,'=>')){
                            throw new Exception('错误函数');
                            //错误内容
                            continue; 
                        }
                        //METHOD 中含有一对括号，但不含大括号视为，一个函数名称，且有参数传递的函数
                        if(strpos($method,'(') && strpos($method,')')){
                            $method2 = substr($method,0,strpos($method,'('));
                            if(!$method2){
                                throw new Exception('函数名称空的');
                                continue;
                            }
                            if(isset($this->handler[$method2])){
                                if($this->handler[$method2] instanceof JSScript){
                                    $method_script[]=$method.'{'.PHP_EOL.$this->handler[$method2]->text().PHP_EOL.'}';
                                }else{
                                    $method_script[]=$method.'{'.PHP_EOL.$this->handler[$method2].PHP_EOL.'}';
                                }
                                unset($this->handler[$method2]);
                            }
                        }else{
                            if(!$method){
                                throw new Exception('函数名称空的');
                                continue;
                            }
                            //METHOD 不匹配以上内容，则直接当函数名称处理
                            if(isset($this->handler[$method])){
                                if($this->handler[$method] instanceof JSScript){
                                    $method_script[]=$method.$this->handler[$method]->argv().'{'.PHP_EOL.$this->handler[$method]->text().PHP_EOL.'}';
                                }else{
                                    $method_script[]=$method.'(event){'.PHP_EOL.$this->handler[$method].PHP_EOL.'}';
                                }
                                unset($this->handler[$method]);
                            }
                        }
                    }
                }

            }elseif(is_string($item)){ //method 的value 为字符串表示函数代码
                $method_script[]=$item;
            }
        }
        foreach($this->handler as $method=>$handle){ 
            if(is_string($handle)){ 
                if(is_numeric($method)){ //若key为数字则视handle为函数定义字符串
                    $method_script[]=$handle;
                }elseif(is_string($method)){ //若key为字符串，则视为函数名称
                    $method_script[]=$method.'(event){'.PHP_EOL.$handle.PHP_EOL.'}';
                }
            }
        }

        //复原
        $this->handler= $lasted;

        $method_script=implode(','.PHP_EOL,$method_script);

        $script_data='let define_data = JSON.parse(`'.json_encode($this->data,JSON_UNESCAPED_UNICODE).'`)';
        $base_script='
            const { createApp } = Vue
            let app = createApp({
            data() {
                return define_data
            },
            methods:{
                '.$method_script.'
            }
            });
            '.$before_mount.'
            let current_app = app.mount("'.$this->query.'")
        ';
        $element2 = new Element('script',true,[],new Text($script_data.PHP_EOL.$base_script.PHP_EOL));
        $html.=$element2->render();
        return $html.PHP_EOL;
    }
    
    /**
     * 返回HTML
     */
    public function script()
    {
        $element = new Element('script',true,[
            'src'=>'https://unpkg.com/vue@3/dist/vue.global.js'
        ]);
        $html = $element->render();
        $html =$this->app_script($html);
        return $html.PHP_EOL;
    }
}